<template>
  <div class="pdf-marking-out-box" @contextmenu.prevent>
    <div class="tool-out-box" :style="{height:toolboxHeight}">
      <slot name="toolbox" :prop="state.prop" :method="state.method">
        <div class="tool-box">
          <div class="tool-box-item search" title="搜索" @click="toggleSearchBoxShow"></div>
          <div class="tool-box-item zoomin" title="放大" @click="zoomin"></div>
          <div class="tool-box-item zoomout" title="缩小" @click="zoomout"></div>
          <div class="tool-box-item rotatecw" title="顺时针旋转" @click="rotateCw"></div>
          <div class="tool-box-item rotateccw" title="逆时针旋转" @click="rotateCcw"></div>
          <div class="tool-box-item pointertype" v-show="pointerType==='text'" title="手形工具"
               @click="setPointerType('hand')"></div>
          <div class="tool-box-item pointertype active" v-show="pointerType==='hand'" title="文本选择工具"
               @click="setPointerType('text')"></div>
          <div class="tool-box-item scrawl" title="涂鸦" @click="scrawl"></div>
          <div class="tool-box-item scrawlshow" v-show="!scrawlShow" title="显示涂鸦" @click="showScrawl"></div>
          <div class="tool-box-item scrawlshow active" v-show="scrawlShow" title="隐藏涂鸦"
               @click="hideScrawl"></div>
          <div class="tool-box-item markshow" v-show="!markShow" title="显示标记" @click="showMark"></div>
          <div class="tool-box-item markshow active" v-show="markShow" title="隐藏标记" @click="hideMark"></div>
        </div>
      </slot>
    </div>
    <div class="container-box" :style="containerBoxStyle">
      <div class="container" :class="'container'+id"
           @focus="handleContainerFocus"
           @blur="handleContainerBlur"
           :style="containerStyle"
           tabindex="1">
        <div class="containerid" :id="'container'+id"></div>
      </div>
      <div class="scroll-bar-box v" :style="getScrollBarStyle('v')">
        <div class="thum" :style="getScrollBarThumStyle('v')" @mousedown="adjustScrollBar('v')"
             @touchstart="adjustScrollBar('v')"></div>
      </div>
      <div class="scroll-bar-box h" :style="getScrollBarStyle('h')">
        <div class="thum" :style="getScrollBarThumStyle('h')" @mousedown="adjustScrollBar('h')"
             @touchstart="adjustScrollBar('h')"></div>
      </div>
      <div class="page-mask" @click="exitScrawl" @contextmenu.prevent="exitClip" v-if="isClip||isScrawl">
        <div class="page-mask-item top"
             :style="{height:maskBound.y+'px',width:`calc(${maskBound.x}px + ${maskBound.width}px)`}"></div>
        <div class="page-mask-item right"
             :style="{width:`calc(100vw - ${maskBound.x}px - ${maskBound.width}px)`,height:`calc(${maskBound.y}px + ${maskBound.height}px)`}"></div>
        <div class="page-mask-item bottom"
             :style="{height:`calc(100vh - ${maskBound.y}px - ${maskBound.height}px)`,width:`calc(100vw - ${maskBound.x}px)`}"></div>
        <div class="page-mask-item left"
             :style="{width:maskBound.x+'px',height:`calc(100vh - ${maskBound.y}px)`}"></div>
        <div class="scrawl-tool" ref="scrawlTool"
             @click.stop
             v-show="isScrawl"
             :style="{left:`${scrawlToolPosition.x}px`,top:`${scrawlToolPosition.y}px`}">
          <div v-if="isExpandScrawlTool" :class="{active:scrawlType==='Line'}" @click="scrawlType='Line'"
               class="scrawl-tool-item line" title="曲线"></div>
          <div v-if="isExpandScrawlTool" :class="{active:scrawlType==='Rect'}" @click="scrawlType='Rect'"
               class="scrawl-tool-item rect" title="矩形"></div>
          <div v-if="isExpandScrawlTool" :class="{active:scrawlType==='Ellipse'}"
               @click="scrawlType='Ellipse'"
               class="scrawl-tool-item ellipse" title="椭圆"></div>
          <div v-if="isExpandScrawlTool" :class="{active:scrawlType==='Arrow'}" @click="scrawlType='Arrow'"
               class="scrawl-tool-item arrow" title="箭头"></div>
          <div v-if="isExpandScrawlTool" :class="{active:scrawlType==='Eraser'}" @click="scrawlType='Eraser'"
               class="scrawl-tool-item eraser" title="橡皮擦"></div>
          <div v-if="isExpandScrawlTool" class="scrawl-tool-item color" title="颜色">
            <input type="color" v-model="brushColor">
          </div>
          <div v-if="isExpandScrawlTool" class="scrawl-tool-item width" title="粗细">
            <select v-model="brushWidth">
              <option :value="10">10</option>
              <option :value="15">15</option>
              <option :value="20">20</option>
              <option :value="30">30</option>
              <option :value="40">40</option>
              <option :value="60">60</option>
              <option :value="80">80</option>
            </select>
          </div>
          <div v-if="isExpandScrawlTool" @click="exitScrawl" class="scrawl-tool-item exit" title="退出"></div>
          <div @click="isExpandScrawlTool=true" class="scrawl-tool-item expand" title="展开工具栏"
               v-if="!isExpandScrawlTool"></div>
          <div @click="isExpandScrawlTool=false" class="scrawl-tool-item collapse" title="折叠工具栏"
               v-if="isExpandScrawlTool"></div>
        </div>
      </div>

      <slot name="searchBox" :prop="state.prop" :method="state.method">
        <div v-show="searchBoxShow" class="marking-search-box"
             :style="{right:`calc(${scrollbarConfig.width} + 20px)`}">
          <div class="input">
            <input type="text" placeholder="搜索..." v-model="searchText" v-focus="searchBoxShow"
                   @keydown.stop.enter="search(searchText)">
            <span class="search-result">{{seachResultIndex}}/{{searchResultCount}}</span>
          </div>
          <div class="btn search" title="搜索" @click="search(searchText)"></div>
          <div class="btn prev" title="上一个" @click="prevSearchResult"></div>
          <div class="btn next" title="下一个" @click="nextSearchResult"></div>
          <div class="btn exit" title="关闭搜索栏" @click="exitSearch"></div>
        </div>
      </slot>
      <div class="loading-mask" v-if="loading">
        <svg class="circular" viewBox="25 25 50 50">
          <circle class="path" cx="50" cy="50" r="20" fill="none"/>
        </svg>
      </div>

      <div class="clip-toolbar" ref="clipToolbar">
        <div class="clip-toolbar-item" @click="exitClip">取消</div>
        <div class="clip-toolbar-item" @click="exitClip(true)">确定</div>
      </div>

      <div class="mark-line"
           v-show="markline&&markShow"
           :ref="`mark${item.markid}`"
           v-for="item in markList"
           :key="item.markid">
        <div class="line" :style="{backgroundColor:marklineColor}" :ref="`linemark${item.markid}`"></div>
        <slot name="markline" :data="item.markline"></slot>
      </div>
    </div>
  </div>
</template>

<script>
  import Konva from 'konva'
  import uuid from 'uuid/v4'
  import MyResizeObserver from '../../../util/MyResizeObserver'
  import getPos from '../../../util/getPos'
  import getContentLength from '../../../util/getContentLength'
  import Hammer from 'hammerjs'
  import ComponentMixins from "@/components/Marking/src/ComponentMixins";

  Konva.showWarnings = false

  const DEBUG = process.env.NODE_ENV !== 'production'

  export default {
    name: "PdfMarking",
    mixins: [ComponentMixins],
    data () {
      return {
        hm: null,
        loadArg: null,
        id: uuid(),
        imageSize: {width: 2479, height: 3508},
        // imageSize: {width: 3508, height: 2479},
        stageSize: {width: 0, height: 0},
        layer: null,

        privateData: {
          scrollTop: 0,
          scrollLeft: 0,
          scaleType: 'page-fit',
          rotation: 0,
          pointerType: 'text',
          seachResultIndex: 0,
          watermark: null
        },
        pageLoading: {},

        brushWidth: 15,
        brushColor: '#ff0000',
        scrawlType: 'Line',

        dx: 0,
        dy: 0,

        isScrawl: false,
        isInScrawlTool: false,
        isExpandScrawlTool: false,
        isClip: false,

        scrawlShow: false,
        markShow: false,

        scrollbar: { // 滚动条显示
          v: false,
          h: false
        },
        dataList: [],
        markList: [],
        scrawlList: [],

        searchBoxShow: false,
        searchText: '',
        searchResultList: [],
        searchResultSelectionList: [],
        isNeedSkipToCurrentSearchResult: false,
        loading: false,
        oldPointerType: '',
        oldScale: 1
      }
    },
    computed: {
      scrollTop: {
        get () {
          return this.privateData.scrollTop
        },
        set (val) {
          if (val < 0) val = 0
          else if (val > this.scrollHeight) val = this.scrollHeight
          this.privateData.scrollTop = val
        }
      },
      scrollLeft: {
        get () {
          return this.privateData.scrollLeft
        },
        set (val) {
          if (this.scrollWidth > 0) {
            if (val < 0 - this.scrollWidth / 2) val = 0 - this.scrollWidth / 2
            else if (val > this.scrollWidth - this.scrollWidth / 2) val = this.scrollWidth - this.scrollWidth / 2
          } else {
            val = 0
          }
          this.privateData.scrollLeft = val
        }
      },
      scaleType: {
        get () {
          return this.privateData.scaleType
        },
        set (val) {
          if (this.isClip || this.isScrawl) return
          if (this.wholePage) val = 'page-fit'
          if (typeof val === 'number') {
            if (val < this.minScale) val = this.minScale
            else if (val > this.maxScale) val = this.maxScale
          }
          this.privateData.scaleType = val

          this.layer.getStage().setAttrs({
            width: this.stageSize.width,
            height: this.stageSize.height,
            offset: {
              x: -this.bigViewSize.width / 2,
              // y: -this.bigViewSize.height / 2
            },
            scale: {x: this.scale, y: this.scale}
          })
        }
      },
      rotation: {
        get () {
          return this.privateData.rotation
        },
        set (val) {
          if (this.isScrawl || this.isClip) return
          val = Math.abs(360 + val) % 360
          this.privateData.rotation = val
        }
      },
      pointerType: {
        get () {
          return this.privateData.pointerType
        },
        set (val) {
          if (val !== 'hand') val = 'text'
          this.privateData.pointerType = val
        }
      },
      seachResultIndex: {
        get () {
          return this.privateData.seachResultIndex
        },
        set (val) {
          if (val < 1) val = this.searchResultCount
          if (val > this.searchResultCount) val = 1
          this.isNeedSkipToCurrentSearchResult = true
          this.privateData.seachResultIndex = val
        }
      },

      halfPageCount () {
        let pageCount = this.pageCount
        if (this.pageCount % 2 !== 0) {
          pageCount -= 1
        }
        if (pageCount < 2) pageCount = 2
        return pageCount / 2
      },
      scale () {
        let scaleType = this.scaleType

        let scale = 1
        if (scaleType === 'page-actual') {
          scale = 1
        } else if (scaleType === 'page-width') {
          scale = this.stageSize.width / this.imageSize.width
        } else if (typeof scaleType === 'number') {
          scale = scaleType
        } else if (scaleType === 'page-fit') {
          scale = Math.min(this.stageSize.width / this.imageSize.width, this.stageSize.height / this.imageSize.height)
        }

        return scale
      },
      containerMinWidth () {
        let minWidth = this.stageSize.height * this.imageSize.width / this.imageSize.height
        return `${minWidth}px`
      },
      minScale () {
        return Math.min(this.stageSize.width / this.imageSize.width, this.stageSize.height / this.imageSize.height)
      },
      containerBoxStyle () {
        let height = '100%'
        if (this.toolboxHeight) height = `calc(100% - ${this.toolboxHeight})`
        return {height}
      },
      containerStyle () {
        let width = '100%'
        let height = '100%'
        if (this.scrollbar.h) {
          height = `calc(100% - ${this.scrollbarConfig.height})`
        }
        if (this.scrollbar.v) {
          width = `calc(100% - ${this.scrollbarConfig.width})`
        }
        let cursor = 'text'
        if (this.isClip) {
          cursor = ''
        }
        return {
          // minWidth: this.containerMinWidth,
          width,
          height,
          cursor
        }
      },
      bigViewSize () {
        return {
          width: this.stageSize.width / this.scale,
          height: this.stageSize.height / this.scale
        }
      },
      scrollHeight () {
        let scrollHeight = this.allHeight - this.bigViewSize.height
        if (scrollHeight < 0) scrollHeight = 0
        this.scrollbar.v = scrollHeight > 0
        return scrollHeight
      },
      scrollWidth () {
        let w = this.imageSize.width
        if ((this.rotation / 90) % 2) {
          w = this.imageSize.height
        }
        let scrollWidth = w - this.bigViewSize.width
        if (scrollWidth < 0) scrollWidth = 0
        this.scrollbar.h = scrollWidth > 0
        return scrollWidth
      },
      progress () {
        return this.scrollHeight ? this.scrollTop / this.scrollHeight : 0
      },
      allHeight () {
        return this.dataList.length * this.imageSize.height
      },
      allWidth () {
        return this.imageSize.width
      },
      currPageIndex () {
        let p = (this.scrollTop + this.bigViewSize.height / 2) / this.allHeight
        let currPageIndex = Math.floor(p * this.dataList.length) || 0
        return currPageIndex
      },
      maskBound () {
        let container = document.querySelector(`.container${this.id}`)
        let maskBound = getPos(container)

        let initY = maskBound.y

        let imageGroup = this.layer.findOne(`.imageGroup${this.currPageIndex}`)

        let scaleX = imageGroup.scaleX()
        let scaleY = imageGroup.scaleY()

        let width = imageGroup.width() * scaleX
        let height = imageGroup.height() * scaleY

        let pos = imageGroup.getAbsolutePosition()

        let deltaX = (maskBound.width - width * this.scale) / 2
        if (deltaX > 0) maskBound.x += deltaX


        let deltaH = maskBound.height - height * this.scale
        if (deltaH < 0) deltaH = 0

        // let deltaY = deltaH / 2 - this.scale * imageGroup.y() + pos.y
        // if (deltaY > 0) maskBound.y += deltaY

        let deltaY = pos.y - height * this.scale / 2
        if (deltaY > 0) maskBound.y += pos.y - height * this.scale / 2

        // 编辑框宽度
        maskBound.width = width * this.scale

        // 编辑框高度
        maskBound.height = height * this.scale
        if (deltaY < 0) {
          maskBound.height -= Math.abs(deltaY)
        }
        // if (imageGroup.parent.height() - height < 100 || deltaY < 0) {
        //   maskBound.height -= Math.abs(deltaY)
        // } else if (deltaY - (imageGroup.parent.height() - height) * this.scale > 0) {
        //   maskBound.height -= deltaY - (imageGroup.parent.height() - height) * this.scale
        // }

        if (maskBound.width > this.stageSize.width) maskBound.width = this.stageSize.width
        if (maskBound.y + maskBound.height > this.stageSize.height) maskBound.height = this.stageSize.height - maskBound.y + initY

        return maskBound
      },
      scrawlToolPosition () {
        let pos = {x: this.maskBound.x, y: this.maskBound.y}
        // await this.awaitRender()

        if (!this.isInScrawlTool) {
          pos.y += this.maskBound.height - 50
        }
        return pos
      },
      searchResultCount () {
        return this.searchResultList.length
      },
    },
    watch: {
      scrollWidth () {
        this.scrollLeft = this.scrollLeft
      },
      scrollHeight () {
        this.scrollTop = this.scrollTop
      },
      currPageIndex () {
        if (isNaN(this.currPageIndex)) return
        this.$emit('page-change', this.currPageIndex)
      },
      progress () {
        if (isNaN(this.scrollHeight) || isNaN(this.currPageIndex) || isNaN(this.progress)) return
        this.$emit('progress-change', {
          scrollHeight: this.scrollHeight,
          pageIndex: this.currPageIndex,
          progress: this.progress
        })
      },
      scale () {
        this.layer.draw()
        if (isNaN(this.scrollHeight) || isNaN(this.currPageIndex) || isNaN(this.progress)) return
        this.$emit('progress-change', {
          scrollHeight: this.scrollHeight,
          pageIndex: this.currPageIndex,
          progress: this.progress
        })
      },
      rotation () {
        this.updatePages()
        if (isNaN(this.scrollHeight) || isNaN(this.currPageIndex) || isNaN(this.progress)) return
        this.$emit('progress-change', {
          scrollHeight: this.scrollHeight,
          pageIndex: this.currPageIndex,
          progress: this.progress
        })
      },
      scrollTop () {
        this.updatePages()
      },
      scrollLeft () {
        this.updatePages()
      },
      scrawlShow () {
        this.drawScrawlList()
      },
      markShow () {
        this.drawMarkList()
      },
      seachResultIndex () {
        this.drawSearchResultList()
      }
    },
    mounted () {
      this.initStage()
    },
    methods: {
      log () {
        if (DEBUG || this.debugger) console.log(...arguments)
      },
      initStage () {
        let stage = new Konva.Stage({container: `container${this.id}`})
        stage.on('contextmenu', ({evt}) => evt.preventDefault())
        this.layer = new Konva.Layer()
        let oldDraw = this.layer.draw
        this.layer.draw = (label) => {
          // console.trace('渲染页面')
          oldDraw.apply(this.layer)
          this.log('渲染页面', label)
        }
        stage.add(this.layer)

        let container = document.querySelector(`.container${this.id}`)
        container.addEventListener('wheel', evt => {
          evt.preventDefault()
          if (this.isScrawl) return
          if (this.isClip) return
          if (this.wholePage) return
          if (evt.ctrlKey) {
            if (evt.wheelDelta > 0) {
              this.zoomin()
            } else if (evt.wheelDelta < 0) {
              this.zoomout()
            }
          } else {
            this.scrollBy({y: -evt.wheelDelta / this.scale})
          }
        })
        container.addEventListener('mousedown', evt => {
          this.autoScrollViewing = false
          if (this.isScrawl) return
          if (this.isClip) return
          if (evt.button === 2 && evt.buttons === 2) { // 右键
            let shape = stage.getIntersection(this.getPointerPositionOnStage(ev))
            if (!shape || !shape.hasName('selection')) this.clearSelection()
            let selection = this.getSelection()
            this.$emit('contextmenu', selection)
          }
          if (evt.button === 0 && evt.buttons === 1) { // 左键
            this.clearSelection()
            this.handleContainerMousedown({screenX: evt.screenX, screenY: evt.screenY})
          }
        })
        container.addEventListener('touchstart', evt => {
          this.autoScrollViewing = false
          if (this.isScrawl) return
          if (this.isClip) return
          if (evt.touches.length > 1) return this.isPrimary = false
          this.oldPointerType = this.pointerType
          let targetTouch = evt.targetTouches[0]
          if (targetTouch.radiusX === 0.5 && targetTouch.radiusY === 0.5) {
            this.pointerType = 'text'
          } else {
            this.pointerType = 'hand'
          }
          this.clearSelection()
          this.handleContainerMousedown({screenX: targetTouch.screenX, screenY: targetTouch.screenY})
        })

        this.hm = new Hammer.Manager(container)
        this.hm.add(new Hammer.Pan())
        this.hm.add(new Hammer.Pinch()).recognizeWith([this.hm.get('pan')])
        this.hm.on('pinchstart pinchmove', this.onPinch)

        new MyResizeObserver(container, arg => {
          if (!arg.width || !arg.height) return
          this.$nextTick(() => {
            this.stageSize.width = arg.width
            this.stageSize.height = arg.height
            this.scaleType = this.scaleType
          })
        }, true)

        // this.updatePages()
      },
      onPinch (ev) {
        if (ev.type === 'pinchstart') this.oldScale = this.scale
        this.scaleType = 0.9 * ev.scale * this.oldScale
      },
      // getWordByPointerPosition () {
      //   let pageIndex = this.getPageIndexByPointerPosition()
      //
      //   let data = this.dataList[pageIndex]
      //   if (!data) return
      //   let text = data.text
      //   if (!text) return
      //   if (!text.words) return
      //   if (!text.rows) return
      //
      //   let pointerPositionOnImageGroup = this.getPointerPositionOnImageGroup()
      //
      //   if (!pointerPositionOnImageGroup) return
      //
      //   let prevRowIndex = -1
      //   let minLineHeight = this.imageSize.height
      //   for (let word of text.words) {
      //     //字内
      //     if (pointerPositionOnImageGroup.x >= word.x1 && pointerPositionOnImageGroup.x <= word.x2 && pointerPositionOnImageGroup.y >= word.y1 && pointerPositionOnImageGroup.y <= word.y2) {
      //       return {
      //         position: pointerPositionOnImageGroup.x > (word.x1 + word.x2) / 2 ? 'right' : 'left',
      //         ...word
      //       }
      //     }
      //   }
      //   for (let word of text.words) {
      //     // 行内
      //     if (pointerPositionOnImageGroup.y >= word.y1 && pointerPositionOnImageGroup.y <= word.y2) {
      //       prevRowIndex = word.rowIndex
      //       break
      //     } else {
      //       // 判断最小间隙
      //       if (prevRowIndex !== word.rowIndex) {
      //         // 换行了
      //         if (pointerPositionOnImageGroup.y - word.y2 > 0) {
      //           // 鼠标上面
      //           if (pointerPositionOnImageGroup.y - word.y2 < minLineHeight) {
      //             minLineHeight = pointerPositionOnImageGroup.y - word.y2
      //             prevRowIndex = word.rowIndex
      //           }
      //         } else if (word.y1 - pointerPositionOnImageGroup.y > 0) {
      //           // 鼠标下面
      //           if (word.y1 - pointerPositionOnImageGroup.y < minLineHeight) {
      //             minLineHeight = word.y1 - pointerPositionOnImageGroup.y
      //             prevRowIndex = word.rowIndex
      //           }
      //         }
      //       }
      //     }
      //   }
      //   // 文字行prevRowIndex
      //   let words = text.rows[prevRowIndex] || []
      //   for (let word of words) {
      //     if (pointerPositionOnImageGroup.x < word.x1 && word.wordIndex === 0) {
      //       // this.log('最左边', word)
      //       return {
      //         position: 'left',
      //         ...word
      //       }
      //     } else if (pointerPositionOnImageGroup.x > word.x2 && word.wordIndex === text.rows[prevRowIndex].length - 1) {
      //       // this.log('最右边', word)
      //       return {
      //         position: 'right',
      //         ...word
      //       }
      //     } else if (pointerPositionOnImageGroup.x >= word.x1 && pointerPositionOnImageGroup.x <= word.x2) {
      //       // this.log('字上面', word)
      //       return {
      //         position: pointerPositionOnImageGroup.x > (word.x1 + word.x2) / 2 ? 'right' : 'left',
      //         ...word
      //       }
      //     }
      //   }
      // },

      getStage () {
        return this.layer.getStage()
      },
      async handleContainerMousedown ({screenX, screenY}) {
        let oldScrollTop = this.scrollTop
        let oldScrollLeft = this.scrollLeft

        let A
        if (this.pointerType === 'text') {
          A = await this.getWordByPointerPosition({screenX, screenY})
          // console.log(A)
        }
        let deltaX = 0
        let deltaY = 0
        let prevTime = Date.now()
        let prevScreenY = screenY
        let v = 0
        const move = async ev => {
          if (ev.type === 'touchmove') {
            if (ev.touches.length > 1) return
            ev = ev.targetTouches[0]
          }
          if (this.pointerType === 'text') {
            let B = await this.getWordByPointerPosition(ev)
            if (!B) return
            if (!A) A = B
            await this.drawSelectionByWordAToWordB(A, B)

            if (!this.wholePage) {
              let pointerPositionOnStage = this.getPointerPositionOnStage(ev)
              if (pointerPositionOnStage.y >= this.stageSize.height - 30) {
                this.scrollBy({y: 10 / this.scale})
              } else if (pointerPositionOnStage.y <= 30) {
                this.scrollBy({y: -10 / this.scale})
              }

              if (pointerPositionOnStage.x >= this.stageSize.width - 30) {
                this.scrollBy({x: 10 / this.scale})
              } else if (pointerPositionOnStage.x <= 30) {
                this.scrollBy({x: -10 / this.scale})
              }
            }
            this.layer.draw()
          } else {
            deltaX = ev.screenX - screenX
            deltaY = ev.screenY - screenY

            if (!this.wholePage) {
              let now = Date.now()
              let movementY = ev.screenY - prevScreenY
              prevScreenY = ev.screenY
              v = movementY / (now - prevTime)
              prevTime = now

              this.scrollTo({
                x: oldScrollLeft - deltaX / this.scale,
                y: oldScrollTop - deltaY / this.scale
              })
            }
            this.updatePages()
          }
        }
        const up = ev => {
          window.removeEventListener("mousemove", move)
          window.removeEventListener("mouseup", up)
          window.removeEventListener("touchmove", move)
          window.removeEventListener("touchend", up)

          if (this.oldPointerType) {
            this.pointerType = this.oldPointerType
            this.oldPointerType = ''
          }

          if (this.wholePage) {
            if (deltaX < -50 || deltaY < -50) {
              this.nextPage()
            } else if (deltaX > 50 || deltaY > 50) {
              this.prevPage()
            }
          }

          let selection = this.getSelection()
          if (selection) this.$emit('selection-change', selection)
          this.autoScrollView(v * 2)
        }

        window.addEventListener("touchmove", move)
        window.addEventListener("touchend", up)

        window.addEventListener("mousemove", move)
        window.addEventListener("mouseup", up)
      },
      autoScrollView (v0) {
        this.log('v0:', v0)
        this.autoScrollViewing = true
        let a = 0.01 * (v0 > 0 ? -1 : 1)
        let startTime = Date.now()
        const getPlusMinus = n => {
          if (Number(n) > 0) return 1
          else if (Number(n) < 0) return -1
          else if (Number(n) === 0) return 0
        }

        let scrollTop = this.scrollTop

        const fn = () => {
          setTimeout(() => {
            let t = Date.now() - startTime
            let v = v0 + a * t
            if (getPlusMinus(v) !== getPlusMinus(v0) || !this.autoScrollViewing) return
            let s = v0 * t + 0.5 * a * t * t
            this.scrollTo({y: scrollTop - s / this.scale})
            this.log('v：', v, 's：', s)
            fn()
          }, 17)
        }
        fn()
      },
      nextPage () {
        this.scrollBy({y: this.imageSize.height})
      },
      prevPage () {
        this.scrollBy({y: -this.imageSize.height})
      },
      // 更新页面
      updatePages () {
        for (let pageIndex = 0; pageIndex < this.dataList.length; pageIndex++) {
          let pageGroups = this.layer.find(`.pageGroup${pageIndex}`)
          if (this.currPageIndex - this.halfPageCount <= pageIndex && pageIndex <= this.currPageIndex + this.halfPageCount) {
            if (pageGroups.length) {
              pageGroups.map((pageGroup, index) => {
                if (index) {
                  pageGroup.destroy()
                } else {
                  let x = pageGroup.x()
                  let y = pageGroup.y()
                  let rotation = pageGroup.rotation()

                  let newX = -this.scrollLeft
                  let newY = this.imageSize.height * pageIndex - this.scrollTop + this.imageSize.height / 2
                  let newRotation = this.rotation
                  if (x !== newX || y !== newY || rotation !== newRotation) {
                    pageGroup.setAttrs({
                      x: -this.scrollLeft,
                      y: this.imageSize.height * pageIndex - this.scrollTop + this.imageSize.height / 2,
                      rotation: this.rotation
                    })
                  }
                }
              })
            } else {
              this.loadPage(pageIndex)
            }

            let imageGroup = this.layer.findOne(`.imageGroup${pageIndex}`)
            if (imageGroup) {
              // 绘制涂鸦
              if (!this.isScrawl) this.drawScrawlList(pageIndex, imageGroup)

              // 绘制选取
              this.drawMarkList()

              // 绘制搜索结果选区
              this.drawSearchResultList()
              // 绘制水印
              this.drawWatermark(imageGroup)
            }
          } else {
            // 不应该存在的页面，需要销毁
            pageGroups.map(pageGroup => pageGroup.destroy())
          }
        }
        this.layer.draw('updatePages')
        // setTimeout(this.updatePages, 16.7)
      },
      drawWatermark (group) {
        if (!group) return
        if (!this.watermark) return;

        let scale = group.scaleX()

        let watermark = JSON.parse(JSON.stringify(this.watermark))

        if (!watermark || typeof watermark !== 'object') return

        if (!watermark.spacing) watermark.spacing = {}

        if (watermark.spacing.x === undefined) watermark.spacing.x = 20

        if (watermark.spacing.y === undefined) watermark.spacing.y = 20

        if (watermark.rotation === undefined) watermark.rotation = 45

        if (watermark.fontSize === undefined) watermark.fontSize = 16

        watermark.spacing.x = watermark.spacing.x / this.minScale / scale
        watermark.spacing.y = watermark.spacing.y / this.minScale / scale
        watermark.fontSize = watermark.fontSize / this.minScale / scale

        if (watermark.color === undefined) watermark.color = 'rgba(255,0,0,0.6)'

        if (watermark.text === undefined) watermark.text = '没有水印文字'


        let width = group.width()
        let height = group.height()
        let spacing = watermark.spacing

        let r = watermark.rotation * Math.PI / 180

        let textWidth = getContentLength(watermark.text) / 2 * watermark.fontSize

        if (textWidth > width) {
          textWidth = width
          watermark.fontSize = width / getContentLength(watermark.text) * 2
        }

        let textHeight = watermark.fontSize * 1.5

        let newTextWidth = Math.abs(textWidth * Math.cos(r) + textHeight * Math.sin(r))
        let newTextHeight = Math.abs(textWidth * Math.sin(r) + textHeight * Math.cos(r))

        let xCount = Math.floor((width + spacing.x) / (spacing.x + newTextWidth))
        let marginX = (width - spacing.x * (xCount - 1) - newTextWidth * xCount) / 2 + newTextWidth / 2

        let yCount = Math.floor((height + spacing.y) / (spacing.y + newTextHeight))
        let marginY = (height - spacing.y * (yCount - 1) - newTextHeight * yCount) / 2 + newTextHeight / 2

        for (let i = 0; i < yCount; i++) {
          for (let j = 0; j < xCount; j++) {
            let isExist = group.findOne(`.watermark${i}_${j}`)
            if (isExist) continue
            let text = new Konva.Text({
              x: marginX + j * (spacing.x + newTextWidth),
              y: marginY + i * (spacing.y + newTextHeight),
              offset: {
                x: textWidth / 2,
                y: textHeight / 2
              },
              rotation: -(watermark.rotation),
              text: watermark.text,
              fontSize: watermark.fontSize,
              fill: watermark.color,
              name: `watermark watermark${i}_${j}`,
              listening: false,
              draggable: false
            })
            group.add(text)
          }
        }
        this.layer.draw('drawWatermark')
      },
      drawScrawlList (pageIndex = this.currPageIndex, group, alwaysShow) {
        if (this.scrawlShow || alwaysShow) {
          if (!group) group = this.layer.findOne(`.imageGroup${pageIndex}`)

          if (!group) return
          this.scrawlList.filter(scrawl => scrawl.pageIndex === pageIndex).map(scrawl => {
            scrawl.data.map(item => {
              if (/(scrawl\w+-\w+-\w+-\w+-\w+)/.test(item.attrs.name)) {
                let isExist = group.findOne(`.${RegExp.$1}`)
                if (isExist) return
                let s = Konva.Node.create(item)
                this.addEventLinsterToScrawlItem(s)
                group.add(s)
              }
            })
            this.layer.draw('drawScrawlList')
          })
        } else {
          this.clearSelection('scrawl')
        }
      },
      async drawMarkList () {
        this.clearSelection('mark')
        // if (this.markShow) {
        // }
        for (let i = 0; i < this.markList.length; i++) {
          let item = this.markList[i]
          let isAlwaysShow = this.alwaysShowMarkTypes.indexOf(item.type) > -1
          // console.log(item)
          let A = await this.getWordByIndexPos(item.start)
          let B = await this.getWordByIndexPos(item.end)
          let tRows = await this.getWrodsAToB(A, B)
          if (tRows) {
            for (let name in tRows) {
              let pageIndex = tRows[name].page
              let imageGroup = this.layer.findOne(`.imageGroup${pageIndex}`)
              let isExist = this.layer.findOne(`.mark${name}`)
              if (isExist) continue
              let config = item.config || {}
              if (!config.stroke && !config.fill) config.fill = 'rgba(0,255,0,0.3)'

              if (this.markShow || isAlwaysShow) {
                this.drawRect({
                  ...tRows[name],
                  type: 'mark',
                  markInfo: item,
                  config: {
                    text: tRows[name].text,
                    start: tRows[name].start,
                    end: tRows[name].end,
                    ...config
                  }
                }, `${item.markid} mark${name}`, imageGroup)
              }
            }
            this.layer.draw('drawMarkList text')
          } else {
            let pageIndex = Number(item.start)
            let imageGroup = this.layer.findOne(`.imageGroup${pageIndex}`)
            if (!imageGroup) return
            let isExist = this.layer.findOne(`.mark${item.markid}`)
            if (isExist) return
            let config = item.config || {}
            if (!config.stroke && !config.fill) {
              config.stroke = 'green'
              config.strokeWidth = 5
            }
            if (this.markShow || isAlwaysShow) {
              this.drawRect({
                ...JSON.parse(item.end),
                type: 'mark',
                markInfo: item,
                config: {
                  ...config
                }
              }, item.markid, imageGroup)
            }
            this.layer.draw('drawMarkList rect')
          }
        }
        // this.markList.map(async item => {
        // })

        // const markList = []
        const names = []
        const marks = this.layer.find(`.mark`)
        marks.map(mark => {
          let markName = mark.name()
          if (/(mark([^ ]+))/.test(markName)) {
            let name = RegExp.$1
            let index = names.indexOf(name)
            if (index > -1) return
            names.push(name)
            // let markid = RegExp.$2
            // this.$refs[name][0].innerHTML = this.$refs[name][0].innerHTML.replace(/{%(\w+)%}/, (words, word) => {
            //   let m = this.markList.find(item => item.markid === markid)
            //   if (!m) return ''
            //   return m.markline[word] || ''
            // })
            if (this.markline) {
              this.$refs[name][0].style.top = `${mark.absolutePosition().y}px`
              this.$refs[`line${name}`][0].style.width = `calc(100vw - ${mark.absolutePosition().x}px)`
            }
            // markList.push(mark)
          }
        })
      },
      drawSearchResultList () {
        if (!this.searchResultCount) {
          return this.clearSelection('search')
        }
        this.searchResultList.map((item, index) => {
          let fill = 'rgba(255,255,0,0.5)'
          if (index === this.seachResultIndex - 1) {
            // 当前选中的选区
            fill = 'rgba(255,150,50,0.5)'
            if (this.isNeedSkipToCurrentSearchResult) {
              this.isNeedSkipToCurrentSearchResult = false
              let start = item[0]
              if (this.wholePage) {
                this.scrollTo({y: start.pageIndex * this.imageSize.height})
              } else {
                let currentTop1 = start.pageIndex * this.imageSize.height + start.y1
                let currentTop2 = start.pageIndex * this.imageSize.height + start.y2
                if (this.scrollTop > currentTop1 || currentTop2 > this.scrollTop + this.bigViewSize.height) {
                  // this.scrollTo({y: currentTop2 - this.viewHeight})
                  this.scrollTo({y: currentTop1})
                }
              }
            }
            // 判断是否需要跳转至选取位置
          }
          let tRows = this.getWrodsAToB(item[0], item[item.length - 1])
          if (tRows) {
            for (let name in tRows) {
              let pageIndex = tRows[name].page
              let imageGroup = this.layer.findOne(`.imageGroup${pageIndex}`)
              if (!imageGroup) continue
              let isExist = this.layer.findOne(`.search${name}`)
              if (isExist) {
                isExist.setAttr('fill', fill)
                this.layer.draw('drawSearchResultList')
                continue
              }
              this.drawRect({
                ...tRows[name],
                type: 'search',
                config: {
                  fill: fill
                }
              }, name, imageGroup)
              this.layer.draw('drawSearchResultList')
            }
          }
        })
      },
      // 加载页面
      async loadPage (pageIndex) {
        try {
          if (this.pageLoading[pageIndex]) return
          this.pageLoading[pageIndex] = true
          if (pageIndex < 0) return
          else if (pageIndex > this.dataList.length - 1) return
          let $pageGroup = this.layer.findOne(`.pageGroup${pageIndex}`)
          if ($pageGroup) return
          this.log(`loadPage---${pageIndex}`)
          let scale = await this.getImageScale(pageIndex)
          let pageGroup = new Konva.Group({
            x: -this.scrollLeft,
            y: this.imageSize.height * pageIndex - this.scrollTop + this.imageSize.height / 2,
            rotation: this.rotation,
            width: this.imageSize.width,
            height: this.imageSize.height,
            offsetX: this.imageSize.width / 2,
            offsetY: this.imageSize.height / 2,
            name: `pageGroup${pageIndex}`
          })
          let img = await this.getImage(pageIndex)
          this.layer.add(pageGroup)
          delete this.pageLoading[pageIndex]
          let imageGroup = new Konva.Group({
            x: this.imageSize.width / 2,
            y: this.imageSize.height / 2,
            width: img.width,
            height: img.height,
            scale: {x: scale, y: scale},
            scaleConf: {
              x: this.imageSize.width / img.width, y: this.imageSize.height / img.height
            },
            offset: {
              x: img.width / 2,
              y: img.height / 2
            },
            name: `imageGroup${pageIndex}`
          })
          pageGroup.add(imageGroup)

          let image = new Konva.Image({
            x: 0,
            y: 0,
            width: img.width,
            height: img.height,
            image: img,
            name: `image${pageIndex}`,
            // strokeWidth: 3,
            // stroke: 'red'
          })
          imageGroup.add(image)
          this.updatePages()
          // this.getText(pageIndex)
        } catch (e) {
          console.error('页面加载失败', e)
        }
      },
      // 打开
      // async load(...arg) {
      //   await this.open(...arg || {})
      // },
      async open (...arg) {
        // {data, scrawlList = [], markList = []}

        try {
          this.loadArg = arg
          this.loading = true
          if (this.loadFn) {
            if (typeof this.loadFn !== 'function') throw new Error('参数 load-fn 必须为一个方法')
            arg = await this.loadFn(...arg)
          } else {
            arg = arg[0]
          }

          this.layer.destroyChildren()
          this.setInitConfig()
          // this.dataList = arg.data || []
          this.dataList = arg.data.map((item, index) => {
            return {
              ...item,
              pageIndex: index,
              text: () => this.getText(item, index)
            }
          })
          this.scrawlList = arg.scrawlList || []
          this.markList = (arg.markList || []).map(item => {
            return {
              markline: {},
              markid: uuid(),
              ...item
            }
          })
          this.updatePages()
        } catch (e) {
          console.error('打开失败', e)
        } finally {
          this.loading = false
        }
      },
      async getImageScale (index) {
        let size = await this.getImageSize(index)
        return Math.min(this.imageSize.width / size.width, this.imageSize.height / size.height)
      },
      getImage (index) {
        let data = this.dataList[index]
        let src = data.img
        return new Promise(async (resolve, reject) => {
          let img = new Image()
          if (this.imageLoadFn) {
            if (typeof this.imageLoadFn !== 'function') return reject(new Error('参数 image-load-fn 必须为一个方法'))
            src = await this.imageLoadFn(src)
          }
          img.src = src
          img.onload = () => resolve(img)
        })
      },
      // async getText (index) {
      //   if (this.textLoadFn) {
      //     if (typeof this.textLoadFn !== 'function') return reject(new Error('参数 text-load-fn 必须为一个方法'))
      //     let data = this.dataList[index]
      //     let text = data.text
      //     if (text) return
      //     let t = await this.textLoadFn(index)
      //     console.log(t)
      //     data.text = t
      //   }
      // },
      async getImageSize (index) {
        let img = await this.getImage(index)
        return {width: img.width, height: img.height}
      },
      getScrollBarStyle (vOrh) {
        let width = 0
        let height = 0
        let right = this.scrollbarConfig.thumSize
        let bottom = this.scrollbarConfig.thumSize

        if (this.scrollbar.h) {
          height = this.scrollbarConfig.height
          bottom = `calc(${this.scrollbarConfig.height} + ${this.scrollbarConfig.thumSize})`
        }
        if (this.scrollbar.v) {
          width = this.scrollbarConfig.width
          right = `calc(${this.scrollbarConfig.width} + ${this.scrollbarConfig.thumSize})`
        }

        if (vOrh === 'v') {
          return {width, bottom}
        } else if (vOrh === 'h') {
          return {height, right}
        }
      },
      getScrollBarThumStyle (vOrh) {
        if (vOrh === 'v') {
          return {
            backgroundColor: this.scrollbarConfig.backgroundColor,
            top: `${this.progress * 100}%`,
            width: '100%',
            height: this.scrollbarConfig.thumSize
          }
        } else if (vOrh === 'h') {
          return {
            backgroundColor: this.scrollbarConfig.backgroundColor,
            height: '100%',
            width: this.scrollbarConfig.thumSize,
            left: `${this.scrollLeft / this.scrollWidth * 100 + 50}%`,
          }
        }
      },
      adjustScrollBar (vOrh) {
        let evt = event

        let target = evt.target.offsetParent

        if (evt.type === 'touchstart') {
          evt = evt.targetTouches[0]
        }

        let x = evt.screenX
        let y = evt.screenY

        let oldScrollTop = this.scrollTop
        let oldScrollLeft = this.scrollLeft

        const move = (ev) => {
          if (ev.type === 'touchmove') {
            ev = ev.targetTouches[0]
          }
          let deltaX = ev.screenX - x
          let deltaY = ev.screenY - y
          if (vOrh === 'v') {
            this.scrollTo({y: oldScrollTop + deltaY / (target.offsetHeight / this.scrollHeight)})
          } else if (vOrh === 'h') {
            this.scrollTo({x: oldScrollLeft + deltaX / (target.offsetWidth / this.scrollWidth)})
          }
        }
        const up = (ev) => {
          window.removeEventListener("touchmove", move)
          window.removeEventListener("touchend", up)
          window.removeEventListener("mousemove", move)
          window.removeEventListener("mouseup", up)
        }
        window.addEventListener("touchmove", move)
        window.addEventListener("touchend", up)
        window.addEventListener("mousemove", move)
        window.addEventListener("mouseup", up)
      },
      clearSelection (type = 'selection', names = []) {
        let selections = this.layer.find(`.${type}`)
        let needDraw = selections.length
        selections.map(selection => {
          // console.log(selection)
          selection.destroy()
        })
        if (needDraw) this.layer.draw()
      },
      async drawSelectionByWordAToWordB (A, B) {
        let tRows = await this.getWrodsAToB(A, B)
        this.clearSelection()
        for (let name in tRows) {
          let pageIndex = tRows[name].page
          let imageGroup = this.layer.findOne(`.imageGroup${pageIndex}`)

          this.drawRect({
            ...tRows[name],
            config: {
              fill: this.selectionBgColor,
              text: tRows[name].text,
              start: tRows[name].start,
              end: tRows[name].end
            }
          }, name, imageGroup)
        }
      },
      // getWrodsAToB (A, B) {
      //   if (!A || !B) return
      //   if (A.pageIndex > B.pageIndex) {
      //     [A, B] = [B, A]
      //   } else if (A.pageIndex === B.pageIndex) {
      //     if (A.index > B.index) {
      //       [A, B] = [B, A]
      //     }
      //   }
      //   let tRows = {}
      //
      //   // AB之间的页
      //   for (let i = A.pageIndex; i <= B.pageIndex; i++) {
      //     let cache = this.dataList[i]
      //     if (!cache) {
      //       this.log(cache, i, this.dataList)
      //       return
      //     }
      //     let text = cache.text
      //     let start = 0
      //     let end = text.words.length - 1
      //     if (i === A.pageIndex && i === B.pageIndex) {
      //       start = A.index
      //       end = B.index
      //     } else if (i === A.pageIndex) {
      //       start = A.index
      //     } else if (i === B.pageIndex) {
      //       end = B.index
      //     }
      //
      //     for (let j = start; j <= end; j++) {
      //       let word = text.words[j]
      //
      //       if (B.pageIndex === A.pageIndex && B.index === A.index) {
      //         if (A.position && B.position && A.position === B.position) continue
      //       } else {
      //         if (word.pageIndex === A.pageIndex && word.index === A.index) {
      //           if (A.position === 'right') continue
      //         }
      //         if (word.pageIndex === B.pageIndex && word.index === B.index) {
      //           if (B.position === 'left') continue
      //         }
      //       }
      //
      //       let name = `${word.pageIndex}_${word.rowIndex}`
      //       if (!tRows[name]) {
      //         tRows[name] = {
      //           page: word.pageIndex,
      //           x: word.x1,
      //           y: word.y1,
      //           width: 0,
      //           height: 0,
      //           text: '',
      //           start: `${word.pageIndex}-${word.index}`,
      //           end: ''
      //         }
      //       }
      //       tRows[name].width = word.x2 - tRows[name].x
      //       tRows[name].height = word.y2 - tRows[name].y
      //       tRows[name].text += word.text
      //       tRows[name].end = `${word.pageIndex}-${word.index}`
      //     }
      //   }
      //   return tRows
      // },
      drawRect ({type = 'selection', x, y, width, height, config = {}, markInfo = {}}, name, group) {
        if (!group) return
        let rect = new Konva.Rect({
          x,
          y,
          width,
          height,
          name: `${type} ${type}${name}`,
          ...config
        })

        rect.on('click', ({evt}) => {
          // console.log('点击事件', markInfo, evt)
          this.$emit('mark-click', markInfo, evt)
        })
        rect.on('mouseenter', ({evt}) => {
          // console.log('鼠标进入事件', markInfo, evt)
          this.$emit('mark-mouseenter', markInfo, evt)
        })

        group.add(rect)
      },
      getSelection () {
        let attrs
        let s = this.layer.find('.selection').map(child => {
          attrs = child.getAttrs()
          if (/(\d+)_(\d+)/.test(attrs.name)) {
            return {
              pageIndex: Number(RegExp.$1),
              rowIndex: Number(RegExp.$2),
              start: attrs.start,
              end: attrs.end,
              text: attrs.text
            }
          }
        })

        s.sort((a, b) => a.pageIndex === b.pageIndex ? a.rowIndex - b.rowIndex : a.pageIndex - b.pageIndex)

        let res = s.reduce((res, item, index) => {
          if (!index) res.start = item.start
          if (index === s.length - 1) res.end = item.end
          if (index) res.text += '\n'
          res.text += item.text

          return res
        }, {text: ''})

        return res.text ? res : null
      },
      restorePage () {
        this.scaleType = 'page-fit'
        this.rotation = 0
        this.skipPage(this.currPageIndex)
        this.clearSelection()
      },
      createShape (type) {
        let shape
        // console.log(event)
        let pointerPositionOnImageGroup = this.getPointerPositionOnImageGroup(event)

        if (type === 'Line') {
          shape = new Konva.Line({
            x: 0,
            y: 0,
            points: [pointerPositionOnImageGroup.x, pointerPositionOnImageGroup.y],
            stroke: this.brushColor,
            strokeWidth: this.brushWidth,
            name: `scrawl${uuid()} scrawl`
          })
        } else if (type === 'Rect') {
          shape = new Konva.Rect({
            x: pointerPositionOnImageGroup.x,
            y: pointerPositionOnImageGroup.y,
            width: 0,
            height: 0,
            stroke: this.brushColor,
            strokeWidth: this.brushWidth,
            name: `scrawl${uuid()} scrawl`
          })
        } else if (type === 'Ellipse') {
          shape = new Konva.Ellipse({
            x: pointerPositionOnImageGroup.x,
            y: pointerPositionOnImageGroup.y,
            radius: {
              x: 0,
              y: 0
            },
            stroke: this.brushColor,
            strokeWidth: this.brushWidth,
            name: `scrawl${uuid()} scrawl`
          })
        } else if (type === 'Arrow') {
          shape = new Konva.Arrow({
            x: 0,
            y: 0,
            points: [pointerPositionOnImageGroup.x, pointerPositionOnImageGroup.y],
            stroke: this.brushColor,
            pointerLength: 50,
            pointerWidth: 30,
            strokeWidth: this.brushWidth,
            name: `scrawl${uuid()} scrawl`
          })
        }
        this.addEventLinsterToScrawlItem(shape)
        return shape
      },
      addEventLinsterToScrawlItem (scrawlItem) {
        if (!scrawlItem) return
        scrawlItem.on('mousemove mouseup touchmove touchend', ({evt}) => {
          if (this.scrawlType !== 'Eraser') return
          switch (evt.type) {
            case 'mouseup':
            case 'touchend':
            case 'touchmove':
              scrawlItem.destroy()
              this.layer.draw()
              break
            case 'mousemove':
              if (evt.buttons === 1) {
                scrawlItem.destroy()
                this.layer.draw()
              }
              break
          }
        })
      },
      setPointerType (pointerType) {
        this.pointerType = pointerType
      },
      scrawl () {
        // this.restorePage()
        this.isScrawl = true
        let imageGroup = this.layer.findOne(`.imageGroup${this.currPageIndex}`)
        if (!imageGroup) return
        this.drawScrawlList(this.currPageIndex, imageGroup, true)
        imageGroup.on("mousedown touchstart", ({evt}) => {
          if (this.scrawlType === 'Eraser') return
          let shape = this.createShape(this.scrawlType)
          imageGroup.add(shape)
          const move = (ev) => {
            let x = this.maskBound.x
            let w = this.$refs.scrawlTool.offsetWidth
            let h = this.$refs.scrawlTool.offsetHeight
            let y = this.maskBound.y + this.maskBound.height - h
            this.isInScrawlTool = ev.pageX >= x && ev.pageX <= x + w && ev.pageY >= y && ev.pageY <= y + h
            let positionOnPageGroup = this.getPointerPositionOnImageGroup(ev, true)
            if (this.scrawlType === 'Line') {
              let points = shape.getAttr('points')
              points.push(positionOnPageGroup.x, positionOnPageGroup.y)
              shape.setAttr('points', points)
            } else if (this.scrawlType === 'Rect') {
              shape.setAttrs({
                width: positionOnPageGroup.x - shape.x(),
                height: positionOnPageGroup.y - shape.y(),
              })
            } else if (this.scrawlType === 'Ellipse') {
              shape.setAttrs({
                offset: {
                  x: -(positionOnPageGroup.x - shape.x()) / 2,
                  y: -(positionOnPageGroup.y - shape.y()) / 2,
                },
                radius: {
                  x: Math.abs((positionOnPageGroup.x - shape.x()) / 2),
                  y: Math.abs((positionOnPageGroup.y - shape.y()) / 2),
                }
              })
            } else if (this.scrawlType === 'Arrow') {
              let points = shape.getAttr('points')
              points[2] = positionOnPageGroup.x
              points[3] = positionOnPageGroup.y
              shape.setAttr('points', points)
            }
            this.layer.draw()
          }
          const up = () => {
            window.removeEventListener("mousemove", move)
            window.removeEventListener("mouseup", up)
            window.removeEventListener("touchmove", move)
            window.removeEventListener("touchend", up)

          }
          window.addEventListener("mousemove", move)
          window.addEventListener("mouseup", up)
          window.addEventListener("touchmove", move)
          window.addEventListener("touchend", up)
        })
      },
      exitScrawl () {
        if (!this.isScrawl) return;
        this.isScrawl = false
        let imageGroup = this.layer.findOne(`.imageGroup${this.currPageIndex}`)
        if (!imageGroup) return
        // this.drawScrawlList(this.currPageIndex, imageGroup)
        imageGroup.off('mousedown touchstart')

        let data = []
        imageGroup.children.map((scrawlItem) => {
          if (/^scrawl/.test(scrawlItem.name())) data.push(scrawlItem.toObject())
        })
        let scrawlData = {pageIndex: this.currPageIndex, data}
        this.setScrawlData(scrawlData)
        this.$emit('scrawl-complete', scrawlData)
      },
      // getWordByIndexPos (pos) {
      //   if (/^(\d+)-(\d+)$/.test(pos)) {
      //     let pageIndex = Number(RegExp.$1)
      //     let index = Number(RegExp.$2)
      //
      //     let data = this.dataList[pageIndex]
      //     return data.text.words[index]
      //   }
      // },
      toggleSearchBoxShow (onlyOpen) {
        this.searchText = ''
        if (onlyOpen === true) {
          this.searchBoxShow = true
          return
        }
        this.searchBoxShow = !this.searchBoxShow
      },
      search (str) {
        this.clearSelection('search')
        if (!this.searchBoxShow) return
        let strs = str.replace(/\s/g, '').split('')
        let allData = []
        let dataArr = []
        for (let i = 0; i < this.dataList.length; i++) {
          let page = this.dataList[i]
          let text = page.text
          if (!text) {
            dataArr = []
            continue
          }
          let words = text.words
          if (!words) {
            dataArr = []
            continue
          }
          for (let j = 0; j < words.length; j++) {
            let word = words[j]
            if (word.text === strs[dataArr.length]) {
              dataArr.push(word)
              if (dataArr.length === strs.length) {
                allData.push(dataArr)
                dataArr = []
              }
            } else if (!/\s/.test(word.text)) {
              dataArr = []
            }
          }
        }
        this.searchResultList = allData
        let isFirstSet = true
        for (let i = 0; i < allData.length; i++) {
          let res = allData[i]
          let currentTop = res[0].pageIndex * this.imageSize.height + res[0].y2

          if (currentTop >= this.scrollTop) {
            if (isFirstSet) {
              isFirstSet = false
              this.seachResultIndex = i + 1
            }
          }

          // let selection = this.getWrodsAToB(res[0], res[res.length - 1])
          // for (let key in selection) {
          //   let value = selection[key]
          //   let searchRes = this.searchResultSelectionList.find(item => item.page === value.page)
          //   if (!searchRes) {
          //     searchRes = {page: value.page, selections: []}
          //     this.searchResultSelectionList.push(searchRes)
          //   }
          //   searchRes.selections.push({key: key, value: value, index: i})
          // }
        }
        if (allData.length && !this.seachResultIndex) this.seachResultIndex = 1
      },
      prevSearchResult () {
        if (!this.searchResultCount) return
        this.seachResultIndex--
      },
      nextSearchResult () {
        if (!this.searchResultCount) return
        this.seachResultIndex++
      },
      exitSearch () {
        this.searchBoxShow = false
        this.searchResultList.splice(0, this.searchResultList.length)
        this.seachResultIndex = 0
      },
      setInitConfig () {
        let initConfig = this.initConfig

        if (initConfig.markShow === undefined) initConfig.markShow = false
        if (initConfig.scrawlShow === undefined) initConfig.scrawlShow = false
        if (initConfig.isExpandScrawlTool === undefined) initConfig.isExpandScrawlTool = false
        if (initConfig.scrollTop === undefined) initConfig.scrollTop = 0
        if (initConfig.scrollLeft === undefined) initConfig.scrollLeft = 0
        if (initConfig.scaleType === undefined) initConfig.scaleType = 'page-fit'
        if (initConfig.rotation === undefined) initConfig.rotation = 0
        if (initConfig.pointerType === undefined) initConfig.pointerType = 'text'
        if (initConfig.dataList === undefined) initConfig.dataList = []
        if (initConfig.markList === undefined) initConfig.markList = []
        if (initConfig.scrawlList === undefined) initConfig.scrawlList = []

        for (let key in initConfig) {
          this[key] = initConfig[key]
        }
      },
      setScrawlData (scrawlData) {
        let index = this.scrawlList.findIndex(scrawlItem => scrawlItem.pageIndex === scrawlData.pageIndex)

        if (index > -1) this.scrawlList.splice(index, 1)

        this.scrawlList.push(scrawlData)
        this.drawScrawlList()
      },
      removeMark (markid) {
        let index = this.markList.findIndex(item => item.markid === markid)
        if (index > -1) this.markList.splice(index, 1)
        let marks = this.layer.find(`.mark${markid}`)
        let needDraw = marks.length
        marks.forEach(child => child.destroy())
        if (needDraw) this.layer.draw()
      },
      async clip () {
        // this.restorePage()
        let imageGroup = this.layer.findOne(`.imageGroup${this.currPageIndex}`)
        if (!imageGroup) return
        let $image = imageGroup.findOne(`.image${this.currPageIndex}`)
        if (!$image) return
        // let img = await new Promise((resolve, reject) => {
        //   let src = imageGroup.toDataURL()
        //   let image = new Image()
        //   image.width = $image.width()
        //   image.height = $image.height()
        //   image.onload = () => {
        //     resolve(image)
        //   }
        //   image.src = src
        // })
        this.isClip = true

        let clipRectBound = {x: 0, y: 0, height: 0, width: 0}
        let x = 0
        // let y = 0
        let pos = imageGroup.getAbsolutePosition()
        let absoluteScale = imageGroup.getAbsoluteScale()
        let re = imageGroup.getClientRect()

        clipRectBound.x = -re.x
        clipRectBound.height = re.height
        clipRectBound.width = re.width

        // let scaleX = imageGroup.getAttr('scaleConf').x
        // let scaleY = imageGroup.getAttr('scaleConf').y
        let scaleX = imageGroup.scaleX()
        let scaleY = imageGroup.scaleY()

        let width = imageGroup.width() * scaleX
        let height = imageGroup.height() * scaleY

        let deltaY = pos.y - height * this.scale / 2
        // if (deltaY > 0) y = pos.y - height * this.scale / 2

        if (deltaY < 0) {
          clipRectBound.y = Math.abs(deltaY)
          clipRectBound.height -= Math.abs(deltaY)
        }
        if (re.y + clipRectBound.height > this.stageSize.height) {
          clipRectBound.height = this.stageSize.height - re.y
        }

        if (clipRectBound.width > this.stageSize.width) {
          clipRectBound.width = this.stageSize.width
        }


        let rect = new Konva.Rect({
          x: clipRectBound.x / absoluteScale.x,
          y: clipRectBound.y / absoluteScale.y,
          width: clipRectBound.width / absoluteScale.x,
          height: clipRectBound.height / absoluteScale.y,
          fill: 'rgba(0,0,0,0.2)',
          name: 'clipRect'
        })
        let shape = new Konva.Image({
          width: 1,
          height: 1,
          name: 'clipImage',
          stroke: 'red',
          // image: img,
          image: $image.image(),
          strokeWidth: 3,
          draggable: true,
          dragBoundFunc: pos => {
            let {x, y} = pos
            let {height, width} = shape.getClientRect()
            let rectPos = rect.getClientRect()
            if (x < rectPos.x) x = rectPos.x
            else if (x + width > rectPos.x + rectPos.width) x = rectPos.x + rectPos.width - width
            if (y < rectPos.y) y = rectPos.y
            else if (y + height > rectPos.y + rectPos.height) y = rectPos.y + rectPos.height - height
            return {x, y}
          }
        })
        const setClipToolbarPosition = () => {
          let re = shape.getClientRect()

          let x = re.x + re.width - this.$refs.clipToolbar.offsetWidth
          let y = re.y + re.height

          let rectPos = rect.getClientRect()
          if (x < rectPos.x) x = re.x
          if (y + this.$refs.clipToolbar.offsetHeight > rectPos.y + rectPos.height) {
            if (re.y - this.$refs.clipToolbar.offsetHeight < 0) {
              y = y - this.$refs.clipToolbar.offsetHeight
            } else {
              x = re.x
              y = re.y - this.$refs.clipToolbar.offsetHeight
            }
          }

          if (x + this.$refs.clipToolbar.offsetWidth > this.stageSize.width) {
            x = this.stageSize.width - this.$refs.clipToolbar.offsetWidth
          }

          this.$refs.clipToolbar.style.left = `${x}px`
          this.$refs.clipToolbar.style.top = `${y}px`
          this.$refs.clipToolbar.style.visibility = 'visible'
        }
        shape.on('dragstart dragend', evt => {
          if (evt.type === 'dragstart') {
            this.$refs.clipToolbar.style.visibility = 'hidden'
          } else if (evt.type === 'dragend') {
            setClipToolbarPosition()
          }
        })
        shape.on('xChange yChange', () => {
          shape.setAttr('crop', {x: shape.x(), y: shape.y()})
        })
        rect.on('mousedown touchstart', ({evt}) => {
          if (evt.type === 'mousedown') {
            if (evt.buttons !== 1) return
          }
          shape.setAttr('listening', false)
          this.$refs.clipToolbar.style.visibility = 'hidden'
          let pointerPositionOnImageGroup = this.getPointerPositionOnImageGroup(evt)
          let startX = pointerPositionOnImageGroup.x
          let startY = pointerPositionOnImageGroup.y

          const move = (ev) => {
            if (ev.type === 'mousemove') {
              if (ev.buttons !== 1) return
            }
            let pointerPositionOnImageGroup = this.getPointerPositionOnImageGroup(ev)

            let moveX = pointerPositionOnImageGroup.x
            let moveY = pointerPositionOnImageGroup.y

            let x = Math.min(startX, moveX)
            let y = Math.min(startY, moveY)
            let width = Math.abs(moveX - startX) || 1
            let height = Math.abs(moveY - startY) || 1
            shape.setAttrs({
              x,
              y,
              width,
              height,
              crop: {
                x,
                y,
                width,
                height
              }
            })
            this.layer.draw()
          }
          const up = () => {
            window.removeEventListener("mousemove", move)
            window.removeEventListener("mouseup", up)
            window.removeEventListener("touchmove", move)
            window.removeEventListener("touchend", up)
            shape.setAttr('listening', true)

            setClipToolbarPosition()
            this.layer.draw()
          }
          window.addEventListener("mousemove", move)
          window.addEventListener("mouseup", up)
          window.addEventListener("touchmove", move)
          window.addEventListener("touchend", up)
        })
        imageGroup.add(rect)
        imageGroup.add(shape)
        this.layer.draw()
      },
      exitClip (isComplete = false) {
        if (!this.isClip) return
        this.isClip = false
        let imageGroup = this.layer.findOne(`.imageGroup${this.currPageIndex}`)
        if (!imageGroup) return
        let clipRect = imageGroup.findOne('.clipRect')
        if (clipRect) clipRect.destroy()
        let clipImage = imageGroup.findOne('.clipImage')
        if (clipImage) {
          if (isComplete === true) {
            clipImage.setAttr('strokeWidth', 0)
            let attrs = clipImage.getAttrs()
            this.$emit('clip-complete', {
              pageIndex: this.currPageIndex,
              x: attrs.x,
              y: attrs.y,
              width: attrs.width,
              height: attrs.height,
              dataURL: clipImage.toDataURL()
            })
          }
          clipImage.destroy()
        }
        this.layer.draw()
        this.$refs.clipToolbar.style.visibility = 'hidden'
      }
    },
    props: {
      markline: {
        type: Boolean,
        default: false
      },
      marklineColor: {
        type: String,
        default: 'black'
      },
      initConfig: {
        type: Object,
        default: () => {
          return {}
        }
      },
      scrollbarConfig: {
        type: Object,
        default: () => {
          return {
            width: '17px',
            height: '17px',
            backgroundColor: '#d9d9d9',
            thumSize: '50px'
          }
        }
      },
      maxScale: {
        type: Number,
        default: 4
      },
      toolboxHeight: {
        type: String,
        default: '30px'
      },
      selectionBgColor: {
        type: String,
        default: 'rgba(0,180,255,0.5)'
      },
      pageCount: {
        type: Number,
        default: 3
      },
      watermark: {
        type: Object,
        default: () => {
          return null
        }
      },
      loadFn: Function,
      imageLoadFn: Function,
      textLoadFn: Function,
      debugger: Boolean,
      wholePage: Boolean
    },
    beforeDestroy () {
      if (this.hm) this.hm.destroy()
    }
  }
</script>

<style lang="scss" scoped>

  .pdf-marking-out-box {
    height: 100%;
    width: 100%;
    position: relative;
    overflow: hidden;
    user-select: none;
    cursor: default;

    .tool-out-box {
      background-color: #f0f0f0;

      .tool-box {
        font-size: 0;
        height: 100%;

        .tool-box-item {
          height: 100%;
          width: 30px;
          display: inline-block;
          /*background-color: green;*/
          margin-left: 10px;
          background-repeat: no-repeat;
          background-position: center;
          background-size: 25px;

          &:nth-child(1) {
            margin-left: 0;
          }

          &.search {
            background-image: url("../../../assets/img/search.png");
          }

          &.zoomin {
            background-image: url("../../../assets/img/zoomin.png");
          }

          &.zoomout {
            background-image: url("../../../assets/img/zoomout.png");
          }

          &.rotatecw {
            background-image: url("../../../assets/img/rotatecw.png");
          }

          &.rotateccw {
            background-image: url("../../../assets/img/rotateccw.png");
          }

          &.pointertype {
            background-image: url("../../../assets/img/pointertype.png");
          }

          &.scrawl {
            background-image: url("../../../assets/img/line_black.png");
          }

          &.scrawlshow {
            background-image: url("../../../assets/img/scrawlshow.png");
          }

          &.markshow {
            background-image: url("../../../assets/img/markshow.png");
          }

          &.active {
            background-color: green;
          }

          &:hover {
            background-color: green;
          }
        }
      }
    }

    .container-box {
      width: 100%;
      position: relative;
      background-color: #f2f2f2;
      overflow: hidden;

      .container {
        outline: none;
        /*background-color: rgba(0, 0, 0, 0.5);*/

        .containerid {
          height: 100%;
          width: 100%;
        }
      }


      .scroll-bar-box {
        position: absolute;

        .thum {
          position: absolute;
        }

        &.v {
          top: 0;
          right: 0;
        }

        &.h {
          bottom: 0;
          left: 0;
        }
      }

      .page-mask {
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: 999999999999;
        pointer-events: none;

        .page-mask-item {
          position: fixed;
          background-color: rgba(0, 0, 0, 0.5);
          pointer-events: all;

          &.top {
            left: 0;
            top: 0;
          }

          &.right {
            top: 0;
            right: 0;
          }

          &.bottom {
            bottom: 0;
            right: 0;
          }

          &.left {
            bottom: 0;
            left: 0;
          }
        }

        $scrawl_tool_height: 50px;

        .scrawl-tool {
          position: absolute;
          z-index: 999999999999;
          height: $scrawl_tool_height;
          background-color: rgba(204, 204, 204, 0.3);
          border-radius: 3px;
          cursor: default !important;
          pointer-events: all;

          .expand {
            width: unset;
          }

          &:hover {
            background-color: #cccccc;
          }

          .scrawl-tool-item {
            display: inline-block;
            width: calc(#{$scrawl_tool_height - 10px});
            height: calc(#{$scrawl_tool_height - 10px});
            margin-left: 5px;
            margin-top: 5px;
            border-radius: 5px;
            cursor: pointer !important;
            background-size: calc(#{$scrawl_tool_height - 20px});
            background-position: center;
            background-repeat: no-repeat;
            vertical-align: top;
            padding: 5px;
            box-sizing: border-box;

            &:nth-last-child(1) {
              margin-right: 5px;
            }

            input[type=color] {
              width: 100%;
              height: 100%;
              border: none;
              vertical-align: top;
              -webkit-appearance: none;
              text-align: center;
              display: inline-block;
              background-color: transparent;
              outline: none;
              padding: 0;
            }

            select {
              width: 100%;
              height: 100%;
              border: none;
              vertical-align: top;
              -webkit-appearance: none;
              display: inline-block;
              background-color: transparent;
              outline: none;
              padding: 0;
              text-align: center;
              text-align-last: center;
            }

            &.line {
              background-image: url("../../../assets/img/line_black.png");
            }

            &.rect {
              background-image: url("../../../assets/img/rect_black.png");
            }

            &.ellipse {
              background-image: url("../../../assets/img/ellipse_black.png");
            }

            &.arrow {
              background-image: url("../../../assets/img/arrow_black.png");
            }

            &.eraser {
              background-image: url("../../../assets/img/eraser_black.png");
            }

            &.color {
            }

            &.width {
            }

            &.exit {
              background-image: url("../../../assets/img/exit.png");
            }

            &.expand {
              background-image: url("../../../assets/img/arrow_right.png");
            }

            &.collapse {
              background-image: url("../../../assets/img/arrow_left.png");
            }

            &:hover {
              background-color: #fff;
            }

            &.active {
              background-color: #fff;
            }

          }
        }
      }

      .marking-search-box {
        position: absolute;
        top: 20px;
        right: 30px;
        height: 30px;
        border: 1px solid black;
        border-radius: 15px;
        overflow: hidden;
        padding: 0 15px;
        font-size: 0;
        background-color: white;

        .input {
          display: inline-block;
          height: 100%;
          position: relative;

          input {
            border: none;
            outline: none;
            box-sizing: border-box;
            height: 100%;
            font-size: 14px;
            vertical-align: top;
            padding-right: 60px;
            cursor: text;
          }

          .search-result {
            font-size: 14px;
            line-height: 30px;
            vertical-align: top;
            margin-left: 5px;
            position: absolute;
            right: 0;
          }
        }

        .btn {
          display: inline-block;
          font-size: 14px;
          height: 20px;
          width: 20px;
          margin-top: 5px;
          background-size: contain;
          background-repeat: no-repeat;
          background-position: center;
          vertical-align: top;
          margin-left: 5px;
          border-radius: 5px;

          &.search {
            background-image: url("../../../assets/img/search.png");
          }

          &.prev {
            background-image: url("../../../assets/img/arrow_left.png");
          }

          &.next {
            background-image: url("../../../assets/img/arrow_right.png");
          }

          &.exit {
            background-image: url("../../../assets/img/exit.png");
          }

          &:hover {
            background-color: #ccc;
          }
        }
      }

      .loading-mask {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: rgba(0, 0, 0, 0.8);

        .circular {
          height: 20%;
          animation: loading-rotate 2s linear infinite;

          position: absolute;
          left: 0;
          right: 0;
          top: 0;
          bottom: 0;
          margin: auto;

          .path {
            animation: loading-dash 1.5s ease-in-out infinite;
            stroke-dasharray: 90, 150;
            stroke-dashoffset: 0;
            stroke-width: 2;
            stroke: #409EFF;
            stroke-linecap: round;
          }
        }


        @keyframes loading-rotate {
          100% {
            -webkit-transform: rotate(360deg);
            transform: rotate(360deg)
          }
        }
        @keyframes loading-dash {
          0% {
            stroke-dasharray: 1, 200;
            stroke-dashoffset: 0
          }
          50% {
            stroke-dasharray: 90, 150;
            stroke-dashoffset: -40px
          }
          100% {
            stroke-dasharray: 90, 150;
            stroke-dashoffset: -120px
          }
        }
      }

      .clip-toolbar {
        position: absolute;
        top: 0;
        background-color: white;
        border-radius: 3px;
        font-size: 0;
        visibility: hidden;

        .clip-toolbar-item {
          display: inline-block;
          font-size: 12px;
          line-height: 30px;
          height: 30px;
          min-width: 30px;
          text-align: center;
          padding: 0 10px;

          &:hover {
            background-color: #cccccc;
          }
        }
      }

      .mark-line {
        position: absolute;
        top: 0;
        right: 0;
        z-index: 5;

        .line {
          position: absolute;
          height: 2px;
          top: 0;
          right: 0;
        }
      }
    }
  }


</style>
